#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "math.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //数据初始化
    pCount = 0;
    timeCount = 0;
    //定时器初始化
    mTimer = new QTimer(this); //采集定时器
    connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot()));

    QFont legendFont = font();
    legendFont.setPointSize(9);
    // 时域波形图初始化
    ui->timePlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
    ui->timePlot->legend->setVisible(true);
    ui->timePlot->legend->setFont(legendFont);
    ui->timePlot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignTop | Qt::AlignLeft);
    ui->timePlot->legend->setBrush(QBrush(QColor(255, 255, 255, 230)));
    ui->timePlot->xAxis->setLabel("Time (s)");
    connect(ui->timePlot, &QCustomPlot::mouseMove, this, &MainWindow::timeMoveEvent);

    // 频域波形图初始化
    ui->freqPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
    ui->freqPlot->legend->setVisible(true);
    ui->freqPlot->legend->setFont(legendFont);
    ui->freqPlot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignTop | Qt::AlignLeft);
    ui->freqPlot->legend->setBrush(QBrush(QColor(255, 255, 255, 230)));
    ui->freqPlot->xAxis->setLabel("Frequency (Hz)");
    connect(ui->freqPlot, &QCustomPlot::mouseMove, this, &MainWindow::freqMoveEvent);

    //载入仿真数据
    loadSimuData();

    //载入设置缓存
    if (mSettings.contains("csvSaveDir"))
    {
        ui->csvDirEdit->setText(mSettings.value("csvSaveDir").toString());
    }
    else
    {
        QString dir = QDir::currentPath();
        ui->csvDirEdit->setText(mSettings.value("csvSaveDir").toString());
    }
}

MainWindow::~MainWindow()
{
    mSettings.setValue("csvSaveDir", ui->csvDirEdit->text());
    delete ui;
}
/*************************************************
**Function:        timerSlot()
**Description:     定时器执行函数
**Input:           无
**Return:          无
**Others:          包括采集数据、绘图、更新信号特征
*************************************************/
void MainWindow::timerSlot()
{
    for (int i = 0; i < ui->singleSampleLen->value(); i++)
    {
        dataTimeX.append(simuData[0][pCount] + 1.0 * timeCount);
        dataTimeY1.append(simuData[ui->signalComboBox1->currentIndex() + 1][pCount]);
        dataTimeY2.append(simuData[ui->signalComboBox2->currentIndex() + 1][pCount]);
        pCount++;
        if (pCount >= 100000)
        {
            timeCount++;
            pCount = 0;
        }
        if (dataTimeX.size() > ui->timeBufferLen->value())
        {
            dataTimeX.remove(0, dataTimeX.size() - ui->timeBufferLen->value());
            dataTimeY1.remove(0, dataTimeY1.size() - ui->timeBufferLen->value());
            dataTimeY2.remove(0, dataTimeY2.size() - ui->timeBufferLen->value());
        }
    }
    plotTimeData();
    plotFreqData();
    updateSignalFearure();
}
/*************************************************
**Function:        plotTimeData()
**Description:     绘制时域波形图
**Input:           无，直接读取全局变量
**Return:          无
**Others:          无
*************************************************/
void MainWindow::plotTimeData()
{
    ui->timePlot->clearGraphs();
    int graphIndex = -1;

    if (ui->ch1CheckBox->isChecked())
    {
        graphIndex++;
        ui->timePlot->addGraph();
        ui->timePlot->graph(graphIndex)->setPen(QPen(Qt::red));
        ui->timePlot->graph(graphIndex)->setName(tr("通道1"));
        ui->timePlot->graph(graphIndex)->setData(dataTimeX, dataTimeY1);
    }
    if (ui->ch2CheckBox->isChecked())
    {
        graphIndex++;
        ui->timePlot->addGraph();
        ui->timePlot->graph(graphIndex)->setPen(QPen(Qt::blue));
        ui->timePlot->graph(graphIndex)->setName(tr("通道2"));
        ui->timePlot->graph(graphIndex)->setData(dataTimeX, dataTimeY2);
    }
    if (ui->timePlotAutoScaleBtn->isChecked())
    {
        ui->timePlot->rescaleAxes();
        if (ui->ch1CheckBox->isChecked() || ui->ch1CheckBox->isChecked())
        {
            ui->timePlot->yAxis->setRangeLower(ui->timePlot->yAxis->range().lower - 0.1);
            ui->timePlot->yAxis->setRangeUpper(ui->timePlot->yAxis->range().upper + 0.1);
        }
    }
    ui->timePlot->replot();
}
/*************************************************
**Function:        plotFreqData()
**Description:     绘制频域波形图
**Input:           无，直接读取全局变量
**Return:          无
**Others:          根据时域进行FFT并绘图
*************************************************/
void MainWindow::plotFreqData()
{
    int fftBits = 16;
    double sampleFreq = ui->sampleFreqSpinBox->value() * 1000;
    ui->freqPlot->clearGraphs();
    int graphIndex = -1;
    if (ui->ch1CheckBox->isChecked())
    {
        if (ui->startSampleBtn->isChecked())
        {
            dataFreqX.clear();
            dataFreqY1.clear();
            dataFreqY1 = DigitalFiltering::fftWithShift(dataTimeY1, fftBits, false);
            dataFreqY1.resize(dataFreqY1.size() / 2);
            dataFreqX.resize(dataFreqY1.size());
            for (int i = 0; i < dataFreqX.size(); i++)
            {
                dataFreqX[i] = ((double)i / (double)dataFreqX.size()) * (sampleFreq / 2.0);
            }
        }
        graphIndex++;
        ui->freqPlot->addGraph();
        ui->freqPlot->graph(graphIndex)->setPen(QPen(Qt::red));
        ui->freqPlot->graph(graphIndex)->setName(tr("通道1"));
        ui->freqPlot->graph(graphIndex)->setData(dataFreqX, dataFreqY1);
    }
    if (ui->ch2CheckBox->isChecked())
    {
        if (ui->startSampleBtn->isChecked())
        {
            dataFreqX.clear();
            dataFreqY2.clear();
            dataFreqY2 = DigitalFiltering::fftWithShift(dataTimeY2, fftBits, false);
            dataFreqY2.resize(dataFreqY2.size() / 2);
            dataFreqX.resize(dataFreqY2.size());
            for (int i = 0; i < dataFreqX.size(); i++)
            {
                dataFreqX[i] = ((double)i / (double)dataFreqX.size()) * (sampleFreq / 2.0);
            }
        }
        graphIndex++;
        ui->freqPlot->addGraph();
        ui->freqPlot->graph(graphIndex)->setPen(QPen(Qt::blue));
        ui->freqPlot->graph(graphIndex)->setName(tr("通道2"));
        ui->freqPlot->graph(graphIndex)->setData(dataFreqX, dataFreqY2);
    }
    if (ui->freqPlotAutoScaleBtn->isChecked())
    {
        ui->freqPlot->rescaleAxes();
    }
    ui->freqPlot->replot();
}
/*************************************************
**Function:        updateSignalFearure()
**Description:     更新信号特征标签
**Input:           无，直接读取全局变量
**Return:          无
**Others:
*************************************************/
void MainWindow::updateSignalFearure()
{
    if (ui->ch1CheckBox->isChecked())
    {
        auto maxFreqY1 = std::max_element(std::begin(dataFreqY1), std::end(dataFreqY1));
        auto pMaxFreqY1 = std::distance(std::begin(dataFreqY1), maxFreqY1);
        ui->ch1FreqLabel->setText(QString("%1Hz").arg(dataFreqX[(int)pMaxFreqY1]));
        ui->ch1PeriodLabel->setText(QString::number(1000 / dataFreqX[(int)pMaxFreqY1], 'f', 3) + "ms");
        auto maxTimeY1 = std::max_element(std::begin(dataTimeY1), std::end(dataTimeY1));
        auto pMaxTimeY1 = std::distance(std::begin(dataTimeY1), maxTimeY1);
        ui->ch1MaxLable->setText(QString("%1").arg(dataTimeY1[(float)pMaxTimeY1]));
        auto minTimeY1 = std::min_element(std::begin(dataTimeY1), std::end(dataTimeY1));
        auto pminTimeY1 = std::distance(std::begin(dataTimeY1), minTimeY1);
        ui->ch1MinLable->setText(QString("%1").arg(dataTimeY1[(float)pminTimeY1]));
    }
    else
    {
        ui->ch1FreqLabel->setText(QString("0"));
        ui->ch1PeriodLabel->setText(QString("0"));
        ui->ch1MaxLable->setText(QString("0"));
        ui->ch1MinLable->setText(QString("0"));
    }
    if (ui->ch2CheckBox->isChecked())
    {
        auto maxFreqY2 = std::max_element(std::begin(dataFreqY2), std::end(dataFreqY2));
        auto pMaxFreqY2 = std::distance(std::begin(dataFreqY2), maxFreqY2);
        ui->ch2FreqLabel->setText(QString("%1Hz").arg(dataFreqX[(int)pMaxFreqY2]));
        ui->ch2PeriodLabel->setText(QString::number(1000 / dataFreqX[(int)pMaxFreqY2], 'f', 3)+"ms");
        auto maxTimeY2 = std::max_element(std::begin(dataTimeY2), std::end(dataTimeY2));
        auto pMaxTimeY2 = std::distance(std::begin(dataTimeY2), maxTimeY2);
        ui->ch2MaxLable->setText(QString("%1").arg(dataTimeY2[(float)pMaxTimeY2]));
        auto minTimeY2 = std::min_element(std::begin(dataTimeY2), std::end(dataTimeY2));
        auto pminTimeY2 = std::distance(std::begin(dataTimeY2), minTimeY2);
        ui->ch2MinLable->setText(QString("%1").arg(dataTimeY2[(float)pminTimeY2]));
    }
    else
    {
        ui->ch2FreqLabel->setText(QString("0"));
        ui->ch2PeriodLabel->setText(QString("0"));
        ui->ch2MaxLable->setText(QString("0"));
        ui->ch2MinLable->setText(QString("0"));
    }
}
void MainWindow::clearSignalFearure(){
    ui->ch1FreqLabel->setText(QString("0"));
    ui->ch1PeriodLabel->setText(QString("0"));
    ui->ch1MaxLable->setText(QString("0"));
    ui->ch1MinLable->setText(QString("0"));

    ui->ch2FreqLabel->setText(QString("0"));
    ui->ch2PeriodLabel->setText(QString("0"));
    ui->ch2MaxLable->setText(QString("0"));
    ui->ch2MinLable->setText(QString("0"));
}
void MainWindow::on_chooseCsvDirBtn_clicked()
{
    QString tempDir = QFileDialog::getExistingDirectory(this,
                                                        "选择数据文件保存位置");
    if (!tempDir.isEmpty())
    {
        ui->csvDirEdit->setText(tempDir);
    }
    else
    {
        ui->statusbar->showMessage("路径未选取", 2000);
        return;
    }
}
/*************************************************
**Function:        loadSimuData()
**Description:     从文件资源中载入仿真数据
**Input:           无
**Return:          无
**Others:          simuData是二维容器
*************************************************/
void MainWindow::loadSimuData()
{
    simuData.clear();
    QFile inFile(":/res/simuData/data.csv");
    if (inFile.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        QTextStream in(&inFile);
        int lineNum = 0;
        QVector<double> data0;
        QVector<double> data1;
        QVector<double> data2;
        QVector<double> data3;
        QVector<double> data4;
        QVector<double> data5;
        QVector<double> data6;
        QVector<double> data7;
        QVector<double> data8;
        QVector<double> data9;

        while (!in.atEnd())
        {
            QStringList tokens = in.readLine().split(",");
            if (lineNum >= 0)
            {
                data0.append(tokens.at(0).toDouble());
                data1.append(tokens.at(1).toDouble());
                data2.append(tokens.at(2).toDouble());
                data3.append(tokens.at(3).toDouble());
                data4.append(tokens.at(4).toDouble());
                data5.append(tokens.at(5).toDouble());
                data6.append(tokens.at(6).toDouble());
                data7.append(tokens.at(7).toDouble());
                data8.append(tokens.at(8).toDouble());
                data9.append(tokens.at(9).toDouble());
            }
            lineNum++;
        }
        inFile.close();
        simuData.append(data0);
        simuData.append(data1);
        simuData.append(data2);
        simuData.append(data3);
        simuData.append(data4);
        simuData.append(data5);
        simuData.append(data6);
        simuData.append(data7);
        simuData.append(data8);
        simuData.append(data9);
        ui->statusbar->showMessage(QString("默认仿真数据加载成功， %1 x %2").arg(simuData.size()).arg(simuData[0].size()), 2000);
    }
    else
    {
        ui->statusbar->showMessage("默认仿真数据加载失败", 2000);
    }
}

/*************************************************
**Function:        loadCsvFile()
**Description:     手动加载数据文件执行函数
**Input:           数据文件地址,以及数据类型
**Return:          是否加载成功
**Others:          1为时域，2为频域
*************************************************/
bool MainWindow::loadCsvFile(QString file, int type)
{
    bool res = false;
    QFile inFile(file);
    switch (type)
    {
    case 1:
    {
        dataTimeX.clear();
        dataTimeY1.clear();
        dataTimeY2.clear();
        break;
    }
    case 2:
    {
        dataFreqX.clear();
        dataFreqY1.clear();
        dataFreqY2.clear();
        break;
    }
    default:
        break;
    }
    if (inFile.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        QTextStream in(&inFile);
        int lineNum = 0;
        while (!in.atEnd())
        {
            QStringList tokens = in.readLine().split(",");
            if (lineNum > 0)
            {
                switch (type)
                {
                case 1:
                {
                    dataTimeX.append(tokens.at(0).toDouble());
                    dataTimeY1.append(tokens.at(1).toDouble());
                    dataTimeY2.append(tokens.at(2).toDouble());
                    break;
                }
                case 2:
                {
                    dataFreqX.append(tokens.at(0).toDouble());
                    dataFreqY1.append(tokens.at(1).toDouble());
                    dataFreqY2.append(tokens.at(2).toDouble());
                    break;
                }
                default:
                    break;
                }
            }
            lineNum++;
        }
        inFile.close();
        switch (type)
        {
        case 1:
        {
            plotTimeData();
            break;
        }
        case 2:
        {
            plotFreqData();
            break;
        }
        default:
            break;
        }
        ui->statusbar->showMessage(QString("文件加载成功,共%1组数据").arg(lineNum), 2000);
        res = true;
    }
    else
    {
        ui->statusbar->showMessage(QString("文件打开失败"), 2000);
    }
    return res;
}

void MainWindow::on_timePlotSavePngBtn_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this,
                                                    tr("Save Time Png"), "",
                                                    tr("PNG Files (*.png)"));

    if (!fileName.isEmpty())
    {
        if (!fileName.toLower().endsWith(".png"))
        {
            fileName.append(".png");
        }
        ui->timePlot->savePng(fileName);
        ui->statusbar->showMessage("时域图像保存成功", 2000);
    }
    else
    {
        ui->statusbar->showMessage("时域图像保存失败", 2000);
    }
}

void MainWindow::updateTimePlotZoom()
{
    Qt::Orientations plotOrientations = Qt::Orientations(
        ((ui->timePlotZoomHBtn->isChecked() ? Qt::Horizontal : 0) |
         (ui->timePlotZoomVBtn->isChecked() ? Qt::Vertical : 0)));

    ui->timePlot->axisRect()->setRangeZoom(plotOrientations);
}

void MainWindow::updateFreqPlotZoom()
{
    Qt::Orientations plotOrientations = Qt::Orientations(
        ((ui->freqPlotZoomHBtn->isChecked() ? Qt::Horizontal : 0) |
         (ui->freqPlotZoomVBtn->isChecked() ? Qt::Vertical : 0)));
    ui->freqPlot->axisRect()->setRangeZoom(plotOrientations);
}

void MainWindow::on_timePlotZoomHBtn_toggled(bool checked)
{
    (void)checked;
    updateTimePlotZoom();
}

void MainWindow::on_stopSampleBtn_clicked()
{
    pCount = 0;
    timeCount = 0;
    dataFreqX.clear();
    dataFreqY1.clear();
    dataFreqY2.clear();
    dataTimeX.clear();
    dataTimeY1.clear();
    dataFreqY2.clear();
    clearSignalFearure();
    on_timePlotClearBtn_clicked();
    on_freqPlotClearBtn_clicked();
    mTimer->stop();
    ui->startSampleBtn->setChecked(false);
    on_startSampleBtn_clicked(false);
}

void MainWindow::on_timePlotZoomVBtn_toggled(bool checked)
{
    (void)checked;
    updateTimePlotZoom();
}

void MainWindow::on_freqPlotZoomHBtn_toggled(bool checked)
{
    (void)checked;
    updateFreqPlotZoom();
}

void MainWindow::on_freqPlotZoomVBtn_toggled(bool checked)
{
    (void)checked;
    updateFreqPlotZoom();
}

void MainWindow::timeMoveEvent(QMouseEvent *event)
{
    double x = event->pos().x();
    double y = event->pos().y();

    double x_ = ui->timePlot->xAxis->pixelToCoord(x);
    double y_ = ui->timePlot->yAxis->pixelToCoord(y);

    QString str = QString("时间: %1\n幅值: %2").arg(QString::number(x_, 10, 3)).arg(QString::number(y_, 10, 3));
    QToolTip::showText(cursor().pos(), str, ui->timePlot);
}

void MainWindow::freqMoveEvent(QMouseEvent *event)
{
    double x = event->pos().x();
    double y = event->pos().y();

    double x_ = ui->freqPlot->xAxis->pixelToCoord(x);
    double y_ = ui->freqPlot->yAxis->pixelToCoord(y);

    QString str = QString("频率: %1Hz\n幅值: %2").arg(QString::number(x_, 10, 3)).arg(QString::number(y_, 10, 3));
    QToolTip::showText(cursor().pos(), str, ui->freqPlot);
}

void MainWindow::on_startSampleBtn_clicked(bool checked)
{
    if (checked)
    {
        dataTimeX.clear();
        dataTimeY1.clear();
        dataTimeY2.clear();
        dataFreqX.clear();
        dataFreqY1.clear();
        dataTimeY2.clear();
        mTimer->start(20);
        ui->startSampleBtn->setStyleSheet("background-color: rgb(85, 255, 127);");
        ui->startSampleBtn->setText("采样中");
        ui->startSampleBtn->setEnabled(false);
        ui->pauseSampleBtn->setEnabled(true);
        ui->restartSampleBtn->setEnabled(true);
    }
    else
    {
        ui->startSampleBtn->setStyleSheet(" ");
        ui->startSampleBtn->setText("开始采样");
        ui->startSampleBtn->setEnabled(true);
        ui->pauseSampleBtn->setEnabled(false);
        ui->restartSampleBtn->setEnabled(false);
    }
}

void MainWindow::on_pauseSampleBtn_clicked()
{
    ui->startSampleBtn->setStyleSheet("color: rgb(255, 121, 3);background-color: rgb(255, 255, 188);");
    ui->startSampleBtn->setText("暂停中");
    mTimer->stop();
}

void MainWindow::on_restartSampleBtn_clicked()
{
    ui->startSampleBtn->setStyleSheet("background-color: rgb(85, 255, 127);");
    ui->startSampleBtn->setText("采样中");
    mTimer->start(20);
}

void MainWindow::on_timePlotClearBtn_clicked()
{
    ui->timePlot->clearGraphs();
    ui->timePlot->replot();
}

void MainWindow::on_freqPlotClearBtn_clicked()
{
    ui->freqPlot->clearGraphs();
    ui->freqPlot->replot();
}

void MainWindow::on_freqPlotScaleBtn_clicked()
{
    ui->freqPlot->rescaleAxes();
    ui->freqPlot->replot();
}

void MainWindow::on_timePlotScaleBtn_clicked()
{
    ui->timePlot->rescaleAxes();
    ui->timePlot->replot();
}

void MainWindow::on_saveTimeDataBtn_clicked()
{
    QString outDirectory = ui->csvDirEdit->text();
    if (outDirectory.startsWith("file:/"))
    {
        outDirectory.remove(0, 6);
    }
    if (!QDir(outDirectory).exists())
    {
        QDir().mkpath(outDirectory);
    }
    if (!QDir(outDirectory).exists())
    {
        QUIWidget::showMessageBoxError("文件保存路径无效");
        return;
    }

    QDateTime d = QDateTime::currentDateTime();
    QFile mRtLogFile;
    mRtLogFile.setFileName(QString("%1/%2-%3-%4_%5-%6-%7-时域数据.csv").arg(outDirectory).arg(d.date().year(), 4, 10, QChar('0')).arg(d.date().month(), 2, 10, QChar('0')).arg(d.date().day(), 2, 10, QChar('0')).arg(d.time().hour(), 2, 10, QChar('0')).arg(d.time().minute(), 2, 10, QChar('0')).arg(d.time().second(), 2, 10, QChar('0')));

    if (mRtLogFile.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        if (mRtLogFile.isOpen())
        {
            QTextStream os(&mRtLogFile);
            os << "dataTimeX"
               << ",";
            os << "dataTimeY1"
               << ",";
            os << "dataTimeY2"
               << ",";
            os << "\n";
            for (int i = 0; i < dataTimeX.size(); i++)
            {
                os << dataTimeX[i] << ",";
                os << dataTimeY1[i] << ",";
                os << dataTimeY2[i] << ",";
                os << "\n";
            }
            os.flush();
            ui->statusbar->showMessage("时域数据文件保存成功", 2000);
        }
    }
    else
    {
        QUIWidget::showMessageBoxError("文件写入错误");
        ui->statusbar->showMessage("文件写入错误", 2000);
    }
}

void MainWindow::on_saveFreqDataBtn_clicked()
{
    QString outDirectory = ui->csvDirEdit->text();
    if (outDirectory.startsWith("file:/"))
    {
        outDirectory.remove(0, 6);
    }
    if (!QDir(outDirectory).exists())
    {
        QDir().mkpath(outDirectory);
    }
    if (!QDir(outDirectory).exists())
    {
        QUIWidget::showMessageBoxError("文件保存路径无效");
        return;
    }

    QDateTime d = QDateTime::currentDateTime();
    QFile mRtLogFile;
    mRtLogFile.setFileName(QString("%1/%2-%3-%4_%5-%6-%7-频域数据.csv").arg(outDirectory).arg(d.date().year(), 4, 10, QChar('0')).arg(d.date().month(), 2, 10, QChar('0')).arg(d.date().day(), 2, 10, QChar('0')).arg(d.time().hour(), 2, 10, QChar('0')).arg(d.time().minute(), 2, 10, QChar('0')).arg(d.time().second(), 2, 10, QChar('0')));

    if (mRtLogFile.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        if (mRtLogFile.isOpen())
        {
            QTextStream os(&mRtLogFile);
            os << "dataFreqX"
               << ",";
            os << "dataFreqY1"
               << ",";
            os << "dataFreqY2"
               << ",";
            os << "\n";
            for (int i = 0; i < dataFreqX.size(); i++)
            {
                os << dataFreqX[i] << ",";
                os << dataFreqY1[i] << ",";
                os << dataFreqY2[i] << ",";
                os << "\n";
            }
            os.flush();
            ui->statusbar->showMessage("频域数据文件保存成功", 2000);
        }
    }
    else
    {
        QUIWidget::showMessageBoxError("文件写入错误");
        ui->statusbar->showMessage("文件写入错误", 2000);
    }
}

void MainWindow::on_loadTimeDataBtn_clicked()
{
    if (ui->startSampleBtn->isChecked())
    {
        QUIWidget::showMessageBoxError("请先停止当前实时采样！");
        return;
    }
    QString fileName = QFileDialog::getOpenFileName(this,
                                                    tr("载入时域数据文件"), "",
                                                    tr("CSV files (*.csv)"));

    if (!fileName.isEmpty())
    {
        loadCsvFile(fileName, 1);
    }
    else
    {
        ui->statusbar->showMessage("文件选取为空", 2000);
    }
}

void MainWindow::on_loadFreqDataBtn_clicked()
{
    if (ui->startSampleBtn->isChecked())
    {
        QUIWidget::showMessageBoxError("请先停止当前实时采样！");
        return;
    }
    QString fileName = QFileDialog::getOpenFileName(this,
                                                    tr("载入频数据文件"), "",
                                                    tr("CSV files (*.csv)"));

    if (!fileName.isEmpty())
    {
        loadCsvFile(fileName, 2);
    }
    else
    {
        ui->statusbar->showMessage("文件选取为空", 2000);
    }
}

void MainWindow::on_freqPlotSavePngBtn_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this,
                                                    tr("Save Frequency Png"), "",
                                                    tr("PNG Files (*.png)"));

    if (!fileName.isEmpty())
    {
        if (!fileName.toLower().endsWith(".png"))
        {
            fileName.append(".png");
        }
        ui->freqPlot->savePng(fileName);
        ui->statusbar->showMessage("频域图像保存成功", 2000);
    }
    else
    {
        ui->statusbar->showMessage("频域图像保存失败", 2000);
    }
}
